/*
 * Copyright 2019 xiaomaoguai.com All right reserved. This software is the
 * confidential and proprietary information of xiaomaoguai.com ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with xiaomaoguai.com.
 */

package com.xiaomaoguai.core.next.hsf.http;

import java.lang.annotation.Annotation;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;

/**
 * 扫描HSF接口并注册，用于快速配置需要使用HTTP请求的HSF接口， 下面演示几种使用方法（不代表全部）：
 *
 * <pre>
 * <code>
 * &#064;Bean
 *    public HsfHttpRequestScannerConfigurer hsfScannerConfigurer() {
 *        String serviceVersion = "1.0.0";
 *        String serverUrl = "http://10.253.19.41:5083";
 *
 *        HsfHttpRequestScannerConfigurer scannerConfigurer = new HsfHttpRequestScannerConfigurer();
 *        scannerConfigurer.setBasePackage("com.xiaomaoguai.core.cdc.service");
 *        scannerConfigurer.setServiceVersion(serviceVersion);
 *        scannerConfigurer.setServerUrl(serverUrl);
 *        return scannerConfigurer;
 *    }
 * </code>
 * </pre>
 *
 * or
 *
 * <pre>
 * <code>
 * &#064;Bean
 *    public HsfHttpRequestScannerConfigurer hsfScannerConfigurer() {
 *        HsfHttpRequestScannerConfigurer scannerConfigurer = new HsfHttpRequestScannerConfigurer();
 *        scannerConfigurer.setBasePackage("com.xiaomaoguai.core.cdc.service");
 *        scannerConfigurer.setServiceVersion("${HSF.version.cdcService}");
 *        scannerConfigurer.setServerUrl("${HSF.serverUrl.cdcService}");
 *        return scannerConfigurer;
 *    }
 * </code>
 * </pre>
 *
 * or
 *
 * <pre>
 * <code>
 * &#064;Bean
 *    public HsfHttpRequestScannerConfigurer hsfScannerConfigurer() {
 *        String serviceVersion = "1.0.0";
 *        String serverUrl = "http://10.253.19.41:5083";
 *        HsfHttpRequestProxy hsfHttpRequestProxy = new HsfHttpRequestProxy(new RestTemplate(), serviceVersion, serverUrl);
 *
 *        HsfHttpRequestScannerConfigurer scannerConfigurer = new HsfHttpRequestScannerConfigurer();
 *        scannerConfigurer.setBasePackage("com.xiaomaoguai.core.cdc.service");
 *        scannerConfigurer.setHsfHttpRequestProxy(hsfHttpRequestProxy);
 *        return scannerConfigurer;
 *    }
 * </code>
 * </pre>
 *
 * or
 *
 * <pre>
 * <code>
 * &#064;Bean
 *    public HsfHttpRequestProxy hsfHttpRequestProxy(RestTemplate restTemplate4HttpClient) {
 *        String serviceVersion = "1.0.0";
 *        String serverUrl = "http://10.253.19.41:5083";
 *        return new HsfHttpRequestProxy(restTemplate4HttpClient, serviceVersion, serverUrl);
 *    }
 *
 * &#064;Bean
 *    public HsfHttpRequestScannerConfigurer hsfScannerConfigurer(HsfHttpRequestProxy hsfHttpRequestProxy) {
 *        HsfHttpRequestScannerConfigurer scannerConfigurer = new HsfHttpRequestScannerConfigurer();
 *        scannerConfigurer.setBasePackage("com.xiaomaoguai.core.cdc.service");
 *        scannerConfigurer.setHsfHttpRequestProxy(hsfHttpRequestProxy);
 *        return scannerConfigurer;
 *    }
 * </code>
 * </pre>
 *
 * @author chenyao
 * @since 2016年8月17日 下午12:53:59
 * @see ClassPathHsfInterfaceScanner
 */
public class HsfHttpRequestScannerConfigurer
        implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
    private String                      beanName;
    private ApplicationContext          applicationContext;
    private String                      basePackage;
    private Class<? extends Annotation> annotationClass;
    private Class<?>                    markerInterface;
    private BeanNameGenerator           beanNameGenerator;
    private HsfHttpRequestProxy         hsfHttpRequestProxy;
    private String                      hsfHttpRequestProxyBeanName;
    private RestTemplate                restTemplate;
    private String                      restTemplateBeanName;
    private String                      serviceVersion;
    private String                      serverUrl;
    private ObjectDeserializer          responseBodyDeserializer;
    private String                      responseBodyDeserializerBeanName;

    @Override
    public void afterPropertiesSet() {
        Assert.notNull(this.basePackage, "Property 'basePackage' is required");
        boolean notSetHsfHttpRequestProxy = this.hsfHttpRequestProxy == null
                && StringUtils.isEmpty(this.hsfHttpRequestProxyBeanName);
        Assert.isTrue(
                !(notSetHsfHttpRequestProxy && StringUtils.isEmpty(this.serviceVersion)
                        && StringUtils.isEmpty(this.serverUrl)),
                "Property 'hsfHttpRequestProxy' is null, 'serviceVersion', 'serverUrl' must be not null");
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        ClassPathHsfInterfaceScanner scanner = new ClassPathHsfInterfaceScanner(registry);
        scanner.setAnnotationClass(this.annotationClass);
        scanner.setMarkerInterface(this.markerInterface);
        scanner.setHsfHttpRequestProxy(this.hsfHttpRequestProxy);
        scanner.setHsfHttpRequestProxyBeanName(this.hsfHttpRequestProxyBeanName);
        scanner.setRestTemplate(this.restTemplate);
        scanner.setRestTemplateBeanName(this.restTemplateBeanName);
        scanner.setServiceVersion(this.serviceVersion);
        scanner.setServerUrl(this.serverUrl);
        scanner.setResponseBodyDeserializer(this.responseBodyDeserializer);
        scanner.setResponseBodyDeserializerBeanName(this.responseBodyDeserializerBeanName);
        scanner.setResourceLoader(this.applicationContext);
        if (this.beanNameGenerator != null) {
            scanner.setBeanNameGenerator(this.beanNameGenerator);
        }
        scanner.registerFilters();
        scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage,
                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Do nothing
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    /**
     * Get the name of the bean in the bean factory that created this bean.
     *
     * @return spring bean name
     */
    public String getBeanName() {
        return beanName;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    /**
     * 要扫描的package
     *
     * @param basePackage 要扫描的package
     * @return {@code HsfHttpRequestScannerConfigurer}
     */
    public HsfHttpRequestScannerConfigurer setBasePackage(String basePackage) {
        this.basePackage = basePackage;
        return this;
    }

    /**
     * 使用注解过滤要扫描的class
     *
     * @param annotationClass 使用注解过滤要扫描的class
     * @return {@code HsfHttpRequestScannerConfigurer}
     */
    public HsfHttpRequestScannerConfigurer setAnnotationClass(Class<? extends Annotation> annotationClass) {
        this.annotationClass = annotationClass;
        return this;
    }

    /**
     * Bean名字生成器
     *
     * @param beanNameGenerator Bean名字生成器
     * @return {@code HsfHttpRequestScannerConfigurer}
     */
    public HsfHttpRequestScannerConfigurer setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
        this.beanNameGenerator = beanNameGenerator;
        return this;
    }

    /**
     * 只注册继承自markerInterface的接口
     *
     * @param markerInterface 只注册继承自markerInterface的接口
     * @return {@code HsfHttpRequestScannerConfigurer}
     */
    public HsfHttpRequestScannerConfigurer setMarkerInterface(Class<?> markerInterface) {
        this.markerInterface = markerInterface;
        return this;
    }

    /**
     * HSF接口使用HTTP请求代理类，如果没有设置此值，下面这三个字段必须设置：
     * <ul>
     * <li>{@link #setRestTemplate(RestTemplate)}（可选）
     * <li>{@link #setServiceVersion(String)}
     * <li>{@link #setServerUrl(String)}
     * </ul>
     *
     * @param hsfHttpRequestProxy HSF接口使用HTTP请求代理类
     * @return {@code HsfHttpRequestScannerConfigurer}
     */
    public HsfHttpRequestScannerConfigurer setHsfHttpRequestProxy(HsfHttpRequestProxy hsfHttpRequestProxy) {
        this.hsfHttpRequestProxy = hsfHttpRequestProxy;
        return this;
    }

    /**
     * 设置 {@link #setHsfHttpRequestProxy(HsfHttpRequestProxy)} 属性对象的Bean name
     *
     * @param hsfHttpRequestProxyBeanName hsfHttpRequestProxy对象的Bean name
     * @return {@code HsfHttpRequestScannerConfigurer}
     */
    public HsfHttpRequestScannerConfigurer setHsfHttpRequestProxyBeanName(String hsfHttpRequestProxyBeanName) {
        this.hsfHttpRequestProxyBeanName = hsfHttpRequestProxyBeanName;
        return this;
    }

    /**
     * 访问Rest服务的客户端，建议此字段设置成具有连接池的单一对象
     *
     * @param restTemplate 访问Rest服务的客户端
     * @return {@code HsfHttpRequestScannerConfigurer}
     * @see #setHsfHttpRequestProxy(HsfHttpRequestProxy)
     */
    public HsfHttpRequestScannerConfigurer setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
        return this;
    }

    /**
     * 设置 {@link #setRestTemplate(RestTemplate)} 属性对象的Bean name
     *
     * @param restTemplateBeanName restTemplate属性对象的Bean name
     * @return {@code HsfHttpRequestScannerConfigurer}
     */
    public HsfHttpRequestScannerConfigurer setRestTemplateBeanName(String restTemplateBeanName) {
        this.restTemplateBeanName = restTemplateBeanName;
        return this;
    }

    /**
     * HSF接口的服务版本，举例：1.0.0，此字段可以使用通配符"${}"获取
     * {@link org.springframework.core.env.Environment} 中的属性
     *
     * @param serviceVersion HSF接口的服务版本
     * @return {@code HsfHttpRequestScannerConfigurer}
     * @see #setHsfHttpRequestProxy(HsfHttpRequestProxy)
     */
    public HsfHttpRequestScannerConfigurer setServiceVersion(String serviceVersion) {
        this.serviceVersion = serviceVersion;
        return this;
    }

    /**
     * HSF服务的HTTP IP地址，举例：http://ip:port，此字段可以使用通配符"${}"获取
     * {@link org.springframework.core.env.Environment} 中的属性
     *
     * @param serverUrl HSF服务的HTTP IP地址
     * @return {@code HsfHttpRequestScannerConfigurer}
     * @see #setHsfHttpRequestProxy(HsfHttpRequestProxy)
     */
    public HsfHttpRequestScannerConfigurer setServerUrl(String serverUrl) {
        this.serverUrl = serverUrl;
        return this;
    }

    /**
     * 使用自定义反序列化类来操作：HSF接口返回的值，解决某些泛型类型、特殊的需求（可选）
     *
     * @param responseBodyDeserializer 使用自定义反序列化类
     * @see #setHsfHttpRequestProxy(HsfHttpRequestProxy)
     */
    public void setResponseBodyDeserializer(ObjectDeserializer responseBodyDeserializer) {
        this.responseBodyDeserializer = responseBodyDeserializer;
    }

    /**
     * 设置 {@link #setResponseBodyDeserializer(ObjectDeserializer)} 属性对象的Bean
     * name
     *
     * @param responseBodyDeserializerBeanName responseBodyDeserializer属性对象的Bean
     */
    public void setResponseBodyDeserializerBeanName(String responseBodyDeserializerBeanName) {
        this.responseBodyDeserializerBeanName = responseBodyDeserializerBeanName;
    }
}
